home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 January: Mac OS SDK / Dev.CD Jan 96 SDK / Dev.CD Jan 96 SDK1.toast / Development Kits (Disc 1) / AOCE / Development Tools / Sample Code / Messaging Service Access Module / Internet PMSAM / Internet PMSAM source / smtp.protocol.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-07  |  8.8 KB  |  385 lines  |  [TEXT/MPS ]

  1. /*-------------------------------------------------------------------
  2.  
  3. AOCE Post Office Protocol (POP) / Simple Mail Transfer Protocol (SMTP)
  4. Mail Service Access Module
  5.  
  6. written by Steve Falkenburg-- MacDTS
  7. ©1991-1993 Apple Computer, Inc.
  8.  
  9. --------------
  10. change history
  11. --------------
  12.  
  13. SJF        02/19/93    update for beta build    b1
  14. SJF        10/29/92    update to a11            a11
  15. SJF        06/08/92    update to a8            a8
  16. SJF        02/15/92    first working version    a4.5
  17. SJF        10/16/91    initial coding            a3
  18.  
  19. ---------------------------------------------------------------------*/
  20.  
  21. #include <ctype.h>
  22. #include <string.h>
  23.  
  24. #include "const.h"
  25. #include "gwerrors.h"
  26. #include "mytypes.h"
  27. #include "globals.h"
  28. #include "utils.h"
  29. #include "parser.h"
  30. #include "network.h"
  31. #include "spoolsystem.h"
  32. #include "smtp.protocol.h"
  33.  
  34. /*    This call takes a FULLY FORMED RFC-822 format message as input, and sends the message
  35.     using SMTP to the specified host
  36.     
  37.     the text is sent in "text" in the form of a zero-terminated C string
  38.     the sender is specified in "fromAddress"
  39.     the SMTP server is specified in "smtpServerAddress"
  40. */
  41.  
  42. OSErr SendSMTP(char *headerText,FSSpec *rawTextContent,char *bccText,char *fromAddress,unsigned long smtpServerAddress)
  43. {
  44.     unsigned long stream;
  45.     Ptr response;
  46.     unsigned long responseLength,contentChunkLen,blockOffset;
  47.     OSErr err,err2;
  48.     char *command,*contentChunk;
  49.     char *lfText;
  50.     
  51.     TCP_FlushBytes();            // flush out old TCP response data
  52.     
  53.     command = nil;
  54.     stream = 0L;
  55.     
  56.     err = AddLF(headerText,&lfText);    // add linefeeds to message
  57.     if (err!=noErr) {
  58.         ExitSMTP(stream,nil,command);
  59.         return err;
  60.     }
  61.  
  62.     command = (char *)NewPtrChk(kSMTPCommandLength);
  63.     if (MemError()!=noErr) {
  64.         return MemError();
  65.     }
  66.     
  67.     err = TCP_CreateStream(&stream);
  68.     if (err!=noErr) {
  69.         ExitSMTP(stream,lfText,command);
  70.         return err;
  71.     }
  72.     
  73.     err = TCP_ActiveOpen(stream,smtpServerAddress,kSMTPPort,kSMTPTimeout);
  74.     if (err!=noErr) {
  75.         ExitSMTP(stream,lfText,command);
  76.         return kInvalidSMTPServer;
  77.     }
  78.     
  79.     /* get introduction message */
  80.         
  81.     err = SMTP_GetResponse(stream,&response,&responseLength);
  82.     if (err!=noErr) {
  83.         ExitSMTP(stream,lfText,command);
  84.         return err;
  85.     }
  86.     else if (!PositiveResponse(response)) {
  87.         DisposPtrChk(response);
  88.         ExitSMTP(stream,lfText,command);
  89.         return kSMTPError;
  90.     }
  91.     DisposPtrChk(response);
  92.     
  93.     /* send "HELO" message */
  94.     
  95.     strcpy(command,"HELO [");
  96.     strcat(command,gOurIPString);
  97.     strcat(command,"]");
  98.     err = SMTP_Command(stream,command,&response,&responseLength);
  99.     if (err!=noErr) {
  100.         ExitSMTP(stream,lfText,command);
  101.         return err;
  102.     }
  103.     else if (!PositiveResponse(response)) {
  104.         DisposPtrChk(response);
  105.         ExitSMTP(stream,lfText,command);
  106.         return kSMTPError;
  107.     }
  108.     DisposPtrChk(response);
  109.     
  110.     /* specify sender with MAIL FROM:<> field */
  111.     
  112.     strcpy(command,"MAIL FROM:<");
  113.     strcat(command,fromAddress);
  114.     strcat(command,">");
  115.     err = SMTP_Command(stream,command,&response,&responseLength);
  116.     if (err!=noErr) {
  117.         ExitSMTP(stream,lfText,command);
  118.         return err;
  119.     }
  120.     else if (!PositiveResponse(response)) {
  121.         DisposPtrChk(response);
  122.         ExitSMTP(stream,lfText,command);
  123.         return kSMTPError;
  124.     }
  125.     DisposPtrChk(response);
  126.  
  127.     /* add message recipients in RCPT TO:<> field */
  128.     
  129.     err = RcptMsg(lfText,stream,"To:");
  130.     if (err!=noErr) {
  131.         ExitSMTP(stream,lfText,command);
  132.         return err;
  133.     }        
  134.     err = RcptMsg(lfText,stream,"Cc:");
  135.     if (err!=noErr) {
  136.         ExitSMTP(stream,lfText,command);
  137.         return err;
  138.     }        
  139.     err = RcptMsg(bccText,stream,"Bcc:");
  140.     if (err!=noErr) {
  141.         ExitSMTP(stream,lfText,command);
  142.         return err;
  143.     }        
  144.     
  145.     /* send DATA command */
  146.     
  147.     err = SMTP_Command(stream,"DATA",&response,&responseLength);
  148.     if (err!=noErr) {
  149.         ExitSMTP(stream,lfText,command);
  150.         return err;
  151.     }
  152.     else if (!PositiveResponse(response)) {
  153.         DisposPtrChk(response);
  154.         ExitSMTP(stream,lfText,command);
  155.         return kSMTPError;
  156.     }
  157.     DisposPtrChk(response);
  158.     
  159.     /* send message header */
  160.     
  161.     err = TCP_Send(stream,lfText,(unsigned short)strlen(lfText),true,kSMTPTimeout);
  162.     if (err!=noErr) {
  163.         ExitSMTP(stream,lfText,command);
  164.         return err;
  165.     }
  166.     
  167.     /* send message contents (as one raw block, in chunks) */
  168.  
  169.     contentChunk = (char *)NewPtrChk(kMaxBufferSize);
  170.     if (MemError()!=noErr) {
  171.         DisposPtrChk(response);
  172.         ExitSMTP(stream,lfText,command);
  173.         return MemError();
  174.     }
  175.     blockOffset = 0;
  176.     do {
  177.         contentChunkLen = kMaxBufferSize;
  178.         err = GetFromSpool(rawTextContent,kRawContentType,kRawContentCreator,0,contentChunk,&contentChunkLen,blockOffset);
  179.         if ((err==noErr)||(err==kMoreData)) {
  180.             err2 = TCP_Send(stream,contentChunk,(unsigned short)contentChunkLen,true,kSMTPTimeout);
  181.             blockOffset += contentChunkLen;
  182.         }
  183.     }
  184.     while ((err2==noErr) && (err==kMoreData));
  185.     DisposPtrChk(contentChunk);
  186.     if (err2!=noErr) {
  187.         ExitSMTP(stream,lfText,command);
  188.         return err2;
  189.     }
  190.     
  191.     /* send message terminator */
  192.     
  193.     err = SMTP_Command(stream,kMessageTerminator,&response,&responseLength);
  194.     if (err!=noErr) {
  195.         ExitSMTP(stream,lfText,command);
  196.         return err;
  197.     }
  198.     else if (!PositiveResponse(response)) {
  199.         DisposPtrChk(response);
  200.         ExitSMTP(stream,lfText,command);
  201.         return kSMTPError;
  202.     }
  203.     DisposPtrChk(response);
  204.  
  205.     /* send QUIT to terminate session */
  206.     
  207.     err = SMTP_Command(stream,"QUIT",&response,&responseLength);
  208.     if (err!=noErr) {
  209.         ExitSMTP(stream,lfText,command);
  210.         return err;
  211.     }
  212.     else if (!PositiveResponse(response)) {
  213.         DisposPtrChk(response);
  214.         ExitSMTP(stream,lfText,command);
  215.         return kSMTPError;
  216.     }
  217.     DisposPtrChk(response);
  218.         
  219.     ExitSMTP(stream,lfText,command);
  220.     return err;
  221. }
  222.  
  223.  
  224. void ExitSMTP(unsigned long stream,Ptr lfText,char *command)
  225. {
  226.     if (lfText)
  227.         DisposPtrChk(lfText);
  228.         
  229.     if (command) {
  230.         DisposPtrChk(command);
  231.         TCP_CloseConnection(stream,kSMTPTimeout);
  232.         TCP_ReleaseStream(stream);
  233.     }
  234. }
  235.     
  236.  
  237.  
  238. /*    RcptMsg determines the recipients of the message and sends commands
  239.     to the SMTP server specifying these people as recipients.
  240. */
  241.  
  242. OSErr RcptMsg(char *text,unsigned long stream,char *header)
  243. {
  244.     OSErr err;
  245.     char *command;
  246.     Ptr response;
  247.     unsigned long responseLength;
  248.     char recipient[256];
  249.     char *endOfHeader,*lineEnd,*curLine,*tmpWord;
  250.     
  251.     endOfHeader = strstr(text,kHeaderTerminator);
  252.     if (!endOfHeader)
  253.         return noErr;
  254.  
  255.     command = (char *)NewPtrChk(kSMTPCommandLength);
  256.     if (MemError()!=noErr) {
  257.         return MemError();
  258.     }
  259.  
  260.     lineEnd = text;
  261.     while (lineEnd < endOfHeader) {
  262.         GetLine(&curLine,&lineEnd);
  263.         if (strstr(curLine,header)==curLine) {
  264.             GetWord(&tmpWord,&curLine);
  265.             while (*curLine && curLine<lineEnd) {
  266.                 GetWord(&tmpWord,&curLine);
  267.                 if (curLine<=lineEnd) {
  268.                     CopyWord(recipient,tmpWord);
  269.                     
  270.                     /* add recipient */
  271.                     strcpy(command,"RCPT TO:<");
  272.                     strcat(command,recipient);
  273.                     strcat(command,">");
  274.                     err = SMTP_Command(stream,command,&response,&responseLength);
  275.                     if (err!=noErr && !PositiveResponse(response)) {
  276.                         DisposPtrChk(command);
  277.                         return err;
  278.                     }
  279.                     DisposPtrChk(response);
  280.  
  281.                 }
  282.             }
  283.         }
  284.     }
  285.  
  286.     DisposPtrChk(command);
  287.     return err;
  288. }
  289.  
  290.  
  291. OSErr SMTP_Command(unsigned long connID,char *command,Ptr *response,unsigned long *responseLength)
  292. {
  293.     Ptr sendCommand;
  294.     unsigned short sendLength;
  295.     OSErr err;
  296.     
  297.     sendLength = strlen(command)+2;
  298.     sendCommand = NewPtrChk((long)sendLength+1);
  299.     if (MemError()!=noErr)
  300.         return MemError();
  301.         
  302.     strcpy(sendCommand,command);
  303.     strcat(sendCommand,kCRLF);
  304.     
  305.     err = TCP_Send(connID,sendCommand,sendLength,true,kSMTPTimeout);
  306.     if (err!=noErr) {
  307.         DisposPtrChk(sendCommand);
  308.         return err;
  309.     }
  310.     
  311.     err = SMTP_GetResponse(connID,response,responseLength);
  312.     DisposPtrChk(sendCommand);
  313.     return err;
  314. }
  315.  
  316.  
  317. OSErr SMTP_GetResponse(unsigned long connID,Ptr *response,unsigned long *responseLength)
  318. {
  319.     OSErr err;
  320.     Boolean inMultiLine;
  321.     unsigned short bytesReceived,bytesLeft,lineBytesReceived;
  322.     Ptr responseBuffer,lineStartPtr;
  323.     unsigned char netByte;
  324.     char extenderString[5];
  325.     
  326.     *response = nil;
  327.     inMultiLine = false;
  328.     bytesReceived = 0;
  329.     bytesLeft = kSMTPCommandLength-1;
  330.     lineBytesReceived = 0;
  331.     
  332.     *response = responseBuffer = NewPtrChk(kSMTPCommandLength);
  333.     if (MemError()!=noErr)
  334.         return MemError();
  335.     *responseBuffer = '\0';
  336.     
  337.     do {
  338.         lineStartPtr = responseBuffer;
  339.         do {
  340.             err = TCP_ReadByte(connID,&netByte,kSMTPTimeout);
  341.             if (err==noErr) {
  342.                 *responseBuffer++ = netByte;
  343.                 *responseBuffer = '\0';
  344.                 bytesReceived++;
  345.                 bytesLeft--;
  346.             }
  347.         } while (err==noErr && bytesLeft>0 && netByte!=LF);
  348.         inMultiLine = CheckExtendedReply(inMultiLine,lineStartPtr,responseBuffer,extenderString);
  349.     } while (inMultiLine);
  350.     
  351.     *responseLength = bytesReceived;
  352.     
  353.     return err;
  354. }
  355.  
  356.  
  357. Boolean CheckExtendedReply(Boolean inExtendedReply,Ptr lineStart,Ptr curPtr,char *extenderString)
  358. {
  359.     if ((curPtr-lineStart) < 4)
  360.         return false;
  361.     
  362.     if (!inExtendedReply && lineStart[3]==kExtenderChar) {
  363.         if (isdigit(lineStart[0]) && isdigit(lineStart[1]) && isdigit(lineStart[2])) {
  364.             BlockMove(lineStart,extenderString,3);
  365.             extenderString[3] = ' ';
  366.             extenderString[4] = '\0';
  367.             return true;
  368.         }
  369.     }
  370.     
  371.     if (inExtendedReply && strncmp(lineStart,extenderString,4)==0)
  372.         return false;
  373.     
  374.     return inExtendedReply;
  375. }
  376.  
  377.  
  378. Boolean PositiveResponse(char *response)
  379. {
  380.     if (*response > '3')
  381.         return false;
  382.     
  383.     return true;
  384. }
  385.